import os
import sys
import time
from collections import OrderedDict

from requests import Session, PreparedRequest
from requests.structures import CaseInsensitiveDict

from bridge.reply import Reply, ReplyType
from channel.chat_channel import ChatChannel
from channel.wechat.wechat_channel import qrCallback
from common.MySQLhelper import get_sql_helper
from common.expired_dict import ExpiredDict
from common.singleton import singleton
from lib import itchat
import io
root_path = os.getcwd()
sys.path.append(root_path)
from bridge.context import *
import scipy.spatial as spt
import json
import pandas as pd
import numpy as np
import requests
import socket
from fastapi import FastAPI
import uvicorn

from pydantic import BaseModel
from datetime import datetime

# encoding:utf-8

import signal
from channel import channel_factory
from common.log import logger
from config import conf, load_config, get_appdata_dir
from plugins import *
import multiprocessing as mp

sqlhelper = get_sql_helper()

class PathParam(BaseModel):
    """
    参数
    """
    object_type: str
    width: float
    height_limit: float
    x1: float
    y1: float
    z1: float
    x2: float
    y2: float
    z2: float


# data = pd.read_csv('ground3.txt', header=None)
# data = np.array(data)
# Loc = pd.read_csv('loc_limit3.txt',header=None)
# Loc = np.array(Loc)

# def tach(item,Loc):
#    th = []
#    for i in range(3,6):
#        if Loc[item-1][i] != 0:
#            th.append(int(Loc[item-1][i]))
#    return th

def log(mode, wd, ht):
    if mode == '1':
        # wd = int(input("输入实体宽度"))
        if wd > 1:
            dis = pd.read_csv('ground3.txt', header=None)
            loc = pd.read_csv('loc_limit3.txt', header=None)
        else:
            dis = pd.read_csv('ground1.txt', header=None)
            loc = pd.read_csv('loc_limit1.txt', header=None)
    else:
        # ht = int(input("输入飞行高度限制"))
        if ht < 10:
            dis = pd.read_csv('ground1.txt', header=None)
            loc = pd.read_csv('loc_limit1.txt', header=None)
        elif 10 <= ht <= 20:
            dis = pd.read_csv('flightdis_10.txt', header=None)
            loc = pd.read_csv('flight_10.txt', header=None)
        elif 20 <= ht <= 30:
            dis = pd.read_csv('flightdis_20.txt', header=None)
            loc = pd.read_csv('flight_20.txt', header=None)
        elif 30 <= ht <= 40:
            dis = pd.read_csv('flightdis_30.txt', header=None)
            loc = pd.read_csv('flight_30.txt', header=None)
        else:
            dis = pd.read_csv('ground1.txt', header=None)
            loc = pd.read_csv('loc_limit1.txt', header=None)

    dis = np.array(dis)
    loc = np.array(loc)

    return dis, loc


def fjs(final, Loc, paths):
    text1 = {}
    text1["id"] = "path 1"
    text1["distance"] = str(final[0][1])
    x = []
    y = []
    z = []
    for i in paths[final[0][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text1["points x"] = [str(a) for a in x]
    text1["points y"] = [str(a) for a in y]
    text1["points z"] = [str(a) for a in z]

    text2 = {}
    text2["id"] = "path 2"
    text2["distance"] = str(final[1][1])
    x = []
    y = []
    z = []
    for i in paths[final[1][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text2["points x"] = [str(a) for a in x]
    text2["points y"] = [str(a) for a in y]
    text2["points z"] = [str(a) for a in z]

    text3 = {}
    text3["id"] = "path 3"
    text3["distance"] = str(final[2][1])
    x = []
    y = []
    z = []
    for i in paths[final[2][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text3["points x"] = [str(a) for a in x]
    text3["points y"] = [str(a) for a in y]
    text3["points z"] = [str(a) for a in z]

    text4 = {}
    text4["id"] = "path 4"
    text4["distance"] = str(final[3][1])
    x = []
    y = []
    z = []
    for i in paths[final[3][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text4["points x"] = [str(a) for a in x]
    text4["points y"] = [str(a) for a in y]
    text4["points z"] = [str(a) for a in z]

    text5 = {}
    text5["id"] = "path 5"
    text5["distance"] = str(final[4][1])
    x = []
    y = []
    z = []
    for i in paths[final[4][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text5["points x"] = [str(a) for a in x]
    text5["points y"] = [str(a) for a in y]
    text5["points z"] = [str(a) for a in z]

    text6 = {}
    text6["id"] = "path 6"
    text6["distance"] = str(final[5][1])
    x = []
    y = []
    z = []
    for i in paths[final[5][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text6["points x"] = [str(a) for a in x]
    text6["points y"] = [str(a) for a in y]
    text6["points z"] = [str(a) for a in z]

    text7 = {}
    text7["id"] = "path 7"
    text7["distance"] = str(final[6][1])
    x = []
    y = []
    z = []
    for i in paths[final[6][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text7["points x"] = [str(a) for a in x]
    text7["points y"] = [str(a) for a in y]
    text7["points z"] = [str(a) for a in z]

    text8 = {}
    text8["id"] = "path 8"
    text8["distance"] = str(final[7][1])
    x = []
    y = []
    z = []
    for i in paths[final[7][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text8["points x"] = [str(a) for a in x]
    text8["points y"] = [str(a) for a in y]
    text8["points z"] = [str(a) for a in z]

    text9 = {}
    text9["id"] = "path 9"
    text9["distance"] = str(final[8][1])
    x = []
    y = []
    z = []
    for i in paths[final[8][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text9["points x"] = [str(a) for a in x]
    text9["points y"] = [str(a) for a in y]
    text9["points z"] = [str(a) for a in z]

    text10 = {}
    text10["id"] = "path 10"
    text10["distance"] = str(final[9][1])
    x = []
    y = []
    z = []
    for i in paths[final[9][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text10["points x"] = [str(a) for a in x]
    text10["points y"] = [str(a) for a in y]
    text10["points z"] = [str(a) for a in z]

    text11 = {}
    text11["id"] = "path 11"
    text11["distance"] = str(final[10][1])
    x = []
    y = []
    z = []
    for i in paths[final[10][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text11["points x"] = [str(a) for a in x]
    text11["points y"] = [str(a) for a in y]
    text11["points z"] = [str(a) for a in z]

    text12 = {}
    text12["id"] = "path 12"
    text12["distance"] = str(final[11][1])
    x = []
    y = []
    z = []
    for i in paths[final[11][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text12["points x"] = [str(a) for a in x]
    text12["points y"] = [str(a) for a in y]
    text12["points z"] = [str(a) for a in z]

    text13 = {}
    text13["id"] = "path 13"
    text13["distance"] = str(final[12][1])
    x = []
    y = []
    z = []
    for i in paths[final[12][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text13["points x"] = [str(a) for a in x]
    text13["points y"] = [str(a) for a in y]
    text13["points z"] = [str(a) for a in z]

    text14 = {}
    text14["id"] = "path 14"
    text14["distance"] = str(final[13][1])
    x = []
    y = []
    z = []
    for i in paths[final[13][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text14["points x"] = [str(a) for a in x]
    text14["points y"] = [str(a) for a in y]
    text14["points z"] = [str(a) for a in z]

    text15 = {}
    text15["id"] = "path 15"
    text15["distance"] = str(final[14][1])
    x = []
    y = []
    z = []
    for i in paths[final[14][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text15["points x"] = [str(a) for a in x]
    text15["points y"] = [str(a) for a in y]
    text15["points z"] = [str(a) for a in z]

    text16 = {}
    text16["id"] = "path 16"
    text16["distance"] = str(final[15][1])
    x = []
    y = []
    z = []
    for i in paths[final[15][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text16["points x"] = [str(a) for a in x]
    text16["points y"] = [str(a) for a in y]
    text16["points z"] = [str(a) for a in z]

    text17 = {}
    text17["id"] = "path 17"
    text17["distance"] = str(final[16][1])
    x = []
    y = []
    z = []
    for i in paths[final[16][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text17["points x"] = [str(a) for a in x]
    text17["points y"] = [str(a) for a in y]
    text17["points z"] = [str(a) for a in z]

    text18 = {}
    text18["id"] = "path 18"
    text18["distance"] = str(final[17][1])
    x = []
    y = []
    z = []
    for i in paths[final[17][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text18["points x"] = [str(a) for a in x]
    text18["points y"] = [str(a) for a in y]
    text18["points z"] = [str(a) for a in z]

    text19 = {}
    text19["id"] = "path 19"
    text19["distance"] = str(final[18][1])
    x = []
    y = []
    z = []
    for i in paths[final[18][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text19["points x"] = [str(a) for a in x]
    text19["points y"] = [str(a) for a in y]
    text19["points z"] = [str(a) for a in z]

    text20 = {}
    text20["id"] = "path 20"
    text20["distance"] = str(final[19][1])
    x = []
    y = []
    z = []
    for i in paths[final[19][0]]:
        x.append(Loc[i - 1][0])
        y.append(Loc[i - 1][1])
        z.append(Loc[i - 1][2])
    text20["points x"] = [str(a) for a in x]
    text20["points y"] = [str(a) for a in y]
    text20["points z"] = [str(a) for a in z]

    textarr = []
    textarr.append(text1)
    textarr.append(text2)
    textarr.append(text3)
    textarr.append(text4)
    textarr.append(text5)
    textarr.append(text6)
    textarr.append(text7)
    textarr.append(text8)
    textarr.append(text9)
    textarr.append(text10)
    textarr.append(text11)
    textarr.append(text12)
    textarr.append(text13)
    textarr.append(text14)
    textarr.append(text15)
    textarr.append(text16)
    textarr.append(text17)
    textarr.append(text18)
    textarr.append(text19)
    textarr.append(text20)

    # jtext = json.dumps(textarr)
    jtext = textarr
    return jtext


def tach(item, Loc):
    th = []
    for i in Loc[item - 1][3:]:
        if i != 0:
            th.append(int(i))
    return th


def dfs(start, index, end, Loc, path, paths):
    path.append(index)
    if index == end:
        paths.append(path.copy())
        path.pop()
    else:
        for item in tach(index, Loc):
            if item not in path:
                dfs(start, item, end, Loc, path, paths)

        path.pop()


# def Astar(start,end,map):


def distance(router, data):
    ret = 0
    for i in range(1, len(router)):
        ret += data[router[i - 1] - 1][router[i] - 1]

    return ret


def find(x, y, map):
    map = map[:, 0:2]
    ckt = spt.cKDTree(data=map, leafsize=5)
    point = np.array([x, y])
    d, x = ckt.query(point)
    return x + 1


def save_json(save_path, data):
    assert save_path.split('.')[-1] == 'json'
    with open(save_path, 'w') as file:
        json.dump(data, file)


def plot(paths, loc, start, end, mode):
    ps = []
    ps.append((float(start[0]), float(start[1]), float(start[2])))
    if mode == '2':
        for i in paths:
            ps.append((loc[i - 1][0], loc[i - 1][1], float(end[2])))
    else:
        for i in paths:
            ps.append((loc[i - 1][0], loc[i - 1][1], loc[i - 1][2]))

    ps.append((float(end[0]), float(end[1]), float(end[2])))

    return ps


def main(mode, wd, hl, x1, y1, z1, x2, y2, z2):
    # mode = input("输入规划对象，1：地面，2：空中")

    data, Loc = log(mode, wd, hl)

    paths = []
    path = []

    # start = input("请输入起点坐标")
    # start = start.split(sep=',')
    start = np.array([x1, y1, z1])
    first = find((start[0] + 608706) / 100, (start[1] - 707683) / 100, Loc)

    # end = input("输入终点坐标")
    # end = end.split(sep=',')
    end = np.array([x2, y2, z2])
    last = find((end[0] + 608706) / 100, (end[1] - 707603) / 100, Loc)

    dfs(first, first, last, Loc, path, paths)

    a = len(paths)

    final = [[] * 2] * a
    for i, p in enumerate(paths):
        final[i] = [i, distance(paths[i], data)]
    final = np.array(final)
    final = final[final[:, 1].argsort()]

    js = []
    for i in range(a):
        if i <= 20:
            json_content = {}
            points_list = []
            stt = {
                'x': start[0],
                'y': start[1],
                'z': start[2]
            }
            points_list.append(stt)
            if mode == '2':
                for a in paths[final[i][0]]:
                    points = {
                        'x': Loc[a - 1][0] * 100 - 608706,
                        'y': Loc[a - 1][1] * 100 + 707683,
                        'z': end[2]
                    }
                    points_list.append(points)
            else:
                for a in paths[final[i][0]]:
                    points = {
                        'x': Loc[a - 1][0] * 100 - 608706,
                        'y': Loc[a - 1][1] * 100 + 707683,
                        'z': Loc[a - 1][2] * 100 + 2740
                    }
                    points_list.append(points)

            edd = {
                'x': end[0],
                'y': end[1],
                'z': end[2]
            }
            points_list.append(edd)
            json_content["points"] = points_list
            js.append(json_content)

    return js


app = FastAPI()

def sigterm_handler_wrap(_signo):
    old_handler = signal.getsignal(_signo)

    def func(_signo, _stack_frame):
        logger.info("signal {} received, exiting...".format(_signo))
        conf().save_user_datas()
        if callable(old_handler):  # check old_handler
            return old_handler(_signo, _stack_frame)
        sys.exit(0)

    signal.signal(_signo, func)


def run():
    try:
        # load config
        load_config()
        # ctrl + c
        sigterm_handler_wrap(signal.SIGINT)
        # kill signal
        sigterm_handler_wrap(signal.SIGTERM)

        # create channel
        channel_name = conf().get("channel_type", "wx")

        if "--cmd" in sys.argv:
            channel_name = "terminal"

        if channel_name == "wxy":
            os.environ["WECHATY_LOG"] = "warn"
            # os.environ['WECHATY_PUPPET_SERVICE_ENDPOINT'] = '127.0.0.1:9001'

        channel = channel_factory.create_channel(channel_name)
        if channel_name in ["wx", "wxy", "terminal", "wechatmp", "wechatmp_service", "wechatcom_app", "wework"]:
            PluginManager().load_plugins()

        # startup channel
        channel.startup()
        print("你好")
        # while True:
        #     #从数据库读消息
        #     reply = Reply()
        #     reply.type = 1
        #     reply.content = "你好"
        #     wxchannel.send(reply)
        #     pass

    except Exception as e:
        logger.error("App startup failed!")
        logger.exception(e)

class SendMessage(BaseModel):  # 继承了BaseModel，定义了People的数据格式
    receiver: str  # 默认了name的值为None
    reply: int  # 默认了age为18
    content: str = "你好"  # 默认了sex为renyao

def message(request):
    kwargs = {'timeout': (10, 60), 'proxies': OrderedDict(), 'stream': False, 'verify': True, 'cert': None}
    session = Session()
    adapter02 = session.get_adapter(url=request.url)
    r = adapter02.send(request, **kwargs)
    return r

@app.post("/send/")
def send(sendMessage: SendMessage):
    # reply = Reply(ReplyType.ERROR, "请再问我一次吧")
    # reply = ReplyType(sendMessage.reply)
    itchat.send(sendMessage.content, toUserName=sendMessage.receiver)
    # logger.info("[WX] sendMsg={}, receiver={}".format(reply, receiver))

@app.post("/sendMsgfg/")
def send(sendMessage: SendMessage):
    request = PreparedRequest()
    request['body'] = None
    request['headers'] = CaseInsensitiveDict()
    # request.headers[]
    {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36', 'Accept-Encoding': 'gzip, deflate', 'Accept': '*/*', 'Connection': 'keep-alive', 'Cookie': 'webwx_data_ticket=gSccWH382c69APxeSdQwC/5M; wxuin=3159255354; mm_lang=zh_CN; webwx_auth_ticket=CIsBELyx1p8BGmBR+sUf2XiCMYSBhFrznU/Mn3c2JRFJlmVCmrCcxir/go71j2J1XfhVGBFgUVcD5m68C/JMftQCN6USyO5UVukqlZ/5F0AJBDRl6qwQ1ItiJ8Xskwt1yI7dobKmqFUg6d8=; webwxuvid=17aba9f44e77a730fdf6f397f95323eee89209b4b30e94d44e2d4ddbd5fffd09; wxloadtime=1702475379_expired; wxpluginkey=1702472461; wxsid=DkeG79mpVRTAqP90; wxuin=3159255354'}
    pass
    # reply = ReplyType(sendMessage.reply)
    # if sendMessage.reply == reply.TEXT:
    #     itchat.send(sendMessage.content, toUserName=sendMessage.receiver)
    #     # logger.info("[WX] sendMsg={}, receiver={}".format(reply, receiver))

class Message(BaseModel):  # 继承了BaseModel，定义了People的数据格式
    userName: str  # 默认了name的值为None
    toUserName: str  # 默认了age为18
    content: str = "你好"  # 默认了sex为renyao
    BaseRequest: str

@app.post("/test_send_msg/")
def sendmsg(message: str):
    itchat.instance.send("你好", toUserName=receiver)
    pass
@app.post("/send_raw_msg/")
def sendmsg(message: Message, msgType=1):


    # # self
    # # messages.send_raw_msg(1, msg, toUserName)
    # pass
    s = requests.Session()
    BaseRequest = eval(message.BaseRequest)
    message.BaseRequest = BaseRequest
    url = 'https://wx2.qq.com/cgi-bin/mmwebwx-bin/webwxsendmsg'
    data = {
        'BaseRequest': message.BaseRequest,
        'Msg': {
            'Type': msgType,
            'Content': message.content,
            'FromUserName': message.userName,
            'ToUserName': (message.toUserName if message.toUserName else message.userName),
            'LocalID': int(time.time() * 1e4),
            'ClientMsgId': int(time.time() * 1e4),
        },
        'Scene': 0, }
    headers = {'ContentType': 'application/json; charset=UTF-8', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36'}
    # cookiesDict = core.s.cookies.get_dict()
    # cookie = sqlhelper.fetch_all(" select cookie from cookie order by create_time desc limit 1; ",
    #                           ())[0]
    #
    # headers['Cookie'] = cookie
    r = s.post(url, headers=headers, data=json.dumps(data, ensure_ascii=False).encode('utf8'))
    return None

if __name__ == "__main__":
    labeling_task = mp.Process(target=run)
    # test
    # result = main('1', 3, 0, -100, 150, 4.3, 75, 230, 4.3)
    # print(result)
    labeling_task.start()
    hostname = socket.gethostname()  # 获取本机计算机名称
    ip = socket.gethostbyname(hostname)  # 获取本机ip
    uvicorn.run("DFS:app", host=str(ip), port=9697)


@singleton
class WechatChannel(ChatChannel):
    NOT_SUPPORT_REPLYTYPE = []

    def __init__(self):
        super().__init__()
        self.receivedMsgs = ExpiredDict(60 * 60)

    def startup(self):
        itchat.instance.receivingRetryCount = 600  # 修改断线超时时间
        # login by scan QRCode
        hotReload = conf().get("hot_reload", False)
        status_path = os.path.join(get_appdata_dir(), "itchat.pkl")
        itchat.auto_login(
            enableCmdQR=2,
            hotReload=hotReload,
            statusStorageDir=status_path,
            qrCallback=qrCallback,
        )
        self.user_id = itchat.instance.storageClass.userName
        self.name = itchat.instance.storageClass.nickName
        # logger.info("Wechat login success, uuid: {}, nickname: {}".format(uuid, self.name))
        # start message listener
        # sqlhelper.insert_one(
        #     "INSERT INTO weixin_info (weixinName, userId) VALUES(%s, %s); ",
        #     (self.name, self.user_id))
        itchat.run()

    # handle_* 系列函数处理收到的消息后构造Context，然后传入produce函数中处理Context和发送回复
    # Context包含了消息的所有信息，包括以下属性
    #   type 消息类型, 包括TEXT、VOICE、IMAGE_CREATE
    #   content 消息内容，如果是TEXT类型，content就是文本内容，如果是VOICE类型，content就是语音文件名，如果是IMAGE_CREATE类型，content就是图片生成命令
    #   kwargs 附加参数字典，包含以下的key：
    #        session_id: 会话id
    #        isgroup: 是否是群聊
    #        receiver: 需要回复的对象
    #        msg: ChatMessage消息对象
    #        origin_ctype: 原始消息类型，语音转文字后，私聊时如果匹配前缀失败，会根据初始消息是否是语音来放宽触发规则
    #        desire_rtype: 希望回复类型，默认是文本回复，设置为ReplyType.VOICE是语音回复

    # 统一的发送函数，每个Channel自行实现，根据reply的type字段发送不同类型的消息
    def send(self, reply: Reply, context: Context):
        receiver = context["receiver"]
        if reply.type == ReplyType.ERROR or reply.type == ReplyType.INFO:
            itchat.send(reply.content, toUserName=receiver)
            logger.info("[WX] sendMsg={}, receiver={}".format(reply, receiver))